﻿#pragma once

#include <qobject.h>
#include <qbytearray.h>
#include <qvector.h>
#include <qtimer.h>

class SerialPortManager;
class LogSaver;

class TurnTableCodec :public QObject
{
  Q_OBJECT

  //各个标志位
public:
  enum DataPackageHead//转台数据包头部
  {
    TurnTable_DeviceNum = 0xdd,//转台号
    TurnTable_NoAxleNum = 0x00,//无轴号
    TurnTable_AxleNumOne = 0x01//轴号1
  };

  enum TurnTableInstructionFlag {//转台指令标记
    TurnTable_Connect = 0x55,//连接转台
    TurnTable_Disconnect = 0xaa,//关闭转台远控
    TurnTable_SetLoad = 0x01,//设置负载
    TurnTable_PowerOn = 0x03,//上电
    TurnTable_PowerOff = 0x04,//下电
    TurnTable_CloseCircuit = 0x05,//闭合
    TurnTable_OpenCircuit = 0x06,//闲置
    TurnTable_Stop = 0x07,//停止
    TurnTable_EmergencyStop = 0x08,//急停
    TurnTable_SearchZero = 0x09,//寻零
    TurnTable_MoveToZero = 0x0a,//回零
    TurnTable_SetPositionMode = 0x0b,//设置位置模式
    TurnTable_SetRateMode = 0x0c,//设置速率模式
    TurnTable_Run = 0x10,//运行
    TurnTable_CurrentState = 0x13,//查询现场数据
    TurnTable_SearchZeroState = 0x15,//寻零状态
    TurnTable_RunningState = 0x16,//查询转台运行状态
    TurnTable_RunningMode = 0x17,//查询转台运行模式
    Thermostat_Connect = 0x40,//连接温箱
    Thermostat_Disconnect = 0x41,//断开温箱连接
    Thermostat_TargetTemperature = 0x42,//设置温箱目标温度
    Thermostat_CurrentTemperature = 0x43,//查询温箱当前温度
    Thermostat_TemperatureRate = 0x44,//设置温箱变温速率
    TurnTable_QuitConsole = 0xc0,//退出转台控制台
    TurnTable_Error = 0xcc//转台错误
  };
  enum ErrorFlag {//转台错误标记
    Error_ProcessState = 0x01,//过程状态错误
    Error_AxleState = 0x02,//轴状态错误
    Error_AxleNum = 0x03,//轴号错误
    Error_CheckSummation = 0x04,//检查和错误
    Error_TurnTableAddress = 0x05,//转台地址错误
    Error_Load = 0x08,//负载错误
    Error_PositionModeOverLimited = 0x11,//位置模式超限
    Error_RateModeOverLimited = 0x12,//速率模式超限
    Error_OtherUnfitCondition = 0x18,//其他不符合条件的错误
    Error_ThermostatTargetTemperatureFailed = 0x1b,//温箱目标温度设置失败
    Error_ThermostatTargetTemperatureOverLimited = 0x1c,//转台目标温度超限
    Error_ThermostatFeedbackError = 0x1d,//转台反馈错误
    Error_Connection = 0x90//转台连接出错
  };

  enum TurnTableLoadMode {//负载模式
    Mode_Unloaded = 0,//空载模式
    Mode_Loaded = 1//负载模式
  };

  enum TurnTableRunningMode
  {//转台运行模式
    Mode_PositionMode = 1,
    Mode_RateMode = 2
  };

  enum TurnTableRunningState
  {//转台运行状态
    State_TurnTableRunning = 1,
    State_TurnTableStoped = 0
  };
  enum TurnTablePowerSupplyState
  {
    State_PowerOn = 1,
    State_PowerOff = 0
  };
  enum TurnTableCircuitState
  {
    State_CircuitClosed = 1,
    State_CircuitOpened = 0
  };
  enum TurnTableAmplifierState
  {
    State_AmplifierBroken = 1,
    State_AmplifierNormal = 0
  };
  enum TargetState
  {
    State_NotReached = 0,
    State_Reached = 1
  };
  enum ConnectionState
  {//连接状态
    State_Disconnected,
    State_Connected,
    State_Connecting
  };
  enum TurnTableSearchZeroState
  {//转台寻零状态
    State_NotSearch = 0,
    State_Searching = 1,
    State_Searched = 2
  };
private:
  QTimer timer_sendInstruction;//发送指令用的计时器
  int timeInterval_sendInstruction = 30;//发送指令间隔30毫秒，不建议修改，不能低于20毫秒，但过高可能会导致程序无法正常运行，建议不大于50
  QVector<QByteArray> instructionQueue;//发送指令队列
  QByteArray dataBuffer;//数据缓冲区
  int dataPackageSize = 16;//数据包长度，单位：字节

  float turnTablePositionUpperLimit = 360;//转台位置上限（绝对值）
  float turnTablePositionLowerLimit = 0;//转台位置下限（绝对值）
  float turnTableRateUpperLimit = 5000;//转台速率上限（绝对值）
  float turnTableRateLowerLimit = 1;//转台速率下限（绝对值）
  float turnTableAccelerationUpperLimit = 100;//转台加速度上限（绝对值）
  float turnTableAccelerationLowerLimit = 1;//转台加速度下限（绝对值）

  SerialPortManager* serialPortManager = Q_NULLPTR;//使用的串口管理器
  LogSaver* logSaver = Q_NULLPTR;
public:
  TurnTableCodec(QObject* parent = Q_NULLPTR);
  ~TurnTableCodec();
signals:
  //发送指令用的信号
  void signal_sendInstruction(QByteArray instruction);
  //转台连接状态信号
  void signal_turnTableConnectionState(ConnectionState connectionState);
  //转台现场数据信号
  void signal_turnTableCurrentState(float position, float rate);
  //转台寻零状态信号
  void signal_turnTableSearchZeroState(TurnTableSearchZeroState turnTableSearchZeroState);
  //转台目标位置状态信号（处于位置模式才有意义）
  void signal_turnTableTargetPositionState(TargetState targetState);
  //转台目标速率状态信号（处于速率模式才有意义）
  void signal_turnTableTargetRateState(TargetState targetState);
  //转台目标停止状态信号（下达停止命令后才有意义）
  void signal_turnTableTargetStop(TargetState targetState);
  //转台电源状态
  void signal_turnTablePowerState(TurnTablePowerSupplyState turnTablePowerSupplyState);
  //转台电路状态
  void signal_turnTableCircuitState(TurnTableCircuitState turnTableCircuitState);
  //转台功放状态
  void signal_turnTableAmplifierState(TurnTableAmplifierState turnTableAmplifierState);
  //转台运行状态
  void signal_turnTableRunningState(TurnTableRunningState turnTableRunningState);
  //转台运行模式
  void signal_turnTableRunningMode(TurnTableRunningMode turnTableRunningMode);
  //温箱当前温度
  void signal_currentThermostatTemperature(float temperature);
  //转台错误信号
  void signal_turnTableError(ErrorFlag errorFlag);
  //转台指令回显
  void signal_instructionEcho(TurnTableInstructionFlag instructionFlag, float arg1, float arg2, float arg3);

  //组装指令
public slots:
  bool sendInstruction(TurnTableInstructionFlag instructionFlag, float arg1, float arg2, float arg3);

  //拆解指令
public slots:
  void slot_decode(QByteArray instruction);

  //代码优化，模块化
private:
  void decode();
  void decode_body();
  void checkRunningState();
  bool checkDataPackageTurnTableDeviceNum();

  void dataBufferDropData(int byteCount);
  void addCheckSummation(QByteArray* instruction);
  void setZeroInBehind(QByteArray* instruction);
  void addInstructionHead(QByteArray* instruction, char axleNum, char instructionFlag);
  void addDataBody(QByteArray* instruction, int data);
  void addDataBody(QByteArray* instruction, float data);
  bool checkCheckSummation();
  void sendInstructionController(QByteArray instruction);

  QByteArray code(char axleNum, char instructionFlag, float data1, float data2, float data3);
  QByteArray code(char axleNum, char instructionFlag);
  QByteArray code(char axleNum, char instructionFlag, int data1);
  int dataBodyToInt(int dataBodyNum);
  float dataBodyToFloat(int dataBodyNum);
  //将转台通讯中的先低后高的四字节数据位转换为整形
  int char4ToInt(char* data);

  //将整形转换为转台通讯中的先低后高的四字节数据位
  char* intToChar4(int data, char* data1);
private slots:
  void slot_timer_sendInstruction_timeOut();

  //geter and seter
public:
  float getTurnTablePositionUpperLimit();
  void setTurnTablePositionUpperLimit(float turnTablePositionUpperLimit);
  float getTurnTablePositionLowerLimit();
  void setTurnTablePositionLowerLimit(float turnTablePositionLowerLimit);
  float getTurnTableRateUpperLimit();
  void setTurnTableRateUpperLimit(float turnTableRateUpperLimit);
  float getTurnTableRateLowerLimit();
  void setTurnTableRateLowerLimit(float turnTableRateLowerLimit);
  float getTurnTableAccelerationUpperLimit();
  void setTurnTableAccelerationUpperLimit(float turnTableAccelerationUpperLimit);
  float getTurnTableAccelerationLowerLimit();
  void setTurnTableAccelerationLowerLimit(float turnTableAccelerationLowerLimit);
  SerialPortManager* getSerialPortManager();
  void setSerialPortManager(SerialPortManager* serialPortManager);
  LogSaver* getLogSaver();
  void setLogSaver(LogSaver* logSaver);
};
